package cn.tenmg.hibernate.plus.utils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import cn.tenmg.dsl.utils.StringUtils;

/**
 * 数据库访问工具类
 * 
 * @author June wjzhao@aliyun.com
 *
 * @since 1.0.0
 */
public class DaoUtils {

	private static final String DELETE_SQL = "DELETE FROM %s %s", WHERE_SQL = "WHERE %s", SQL_STRING = "'%s'";

	public static String delete(Class<?> p, Serializable id) {
		String tableName = getTableName(p);
		List<String> idNames = getIdColumnNames(p);
		return String.format(DELETE_SQL, tableName, String.format(WHERE_SQL, idCondition(idNames, id)));
	}

	public static List<String> getIdColumnNames(Class<?> entity) {
		Field[] fields = entity.getDeclaredFields();
		if (fields == null || fields.length <= 0) {
			throw new IllegalArgumentException("Error: Here is no fields in Entity Class: " + entity.getName() + "!");
		}
		List<String> idColumnNames = new ArrayList<String>();
		int count = 0;
		for (Field field : fields) {
			Id id = field.getAnnotation(Id.class);
			if (id != null) {
				String columnName = getColumnName(field);
				idColumnNames.add(columnName);
				count++;
			}
		}
		if (count == 0) {
			throw new IllegalArgumentException(
					"Error: Here is not any id field in Entity Class: " + entity.getName() + "!");
		}
		return idColumnNames;
	}

	/**
	 * 获取实体类对应的数据库表名
	 * 
	 * @param entity
	 *            实体类
	 * @return 返回表名
	 */
	public static String getTableName(Class<?> entity) {
		Table table = entity.getAnnotation(Table.class);
		if (table == null) {
			throw new IllegalArgumentException("Error: Entity @Table Not Found!");
		}
		String tableName = table.name();
		return StringUtils.isNotEmpty(tableName) ? tableName : entity.getClass().getSimpleName().toLowerCase();
	}

	/**
	 * 获取指定字段对应的数据库列名
	 * 
	 * @param field
	 *            指定字段
	 * @return 返回列名
	 */
	public static String getColumnName(Field field) {
		String columnName = null;
		Column column = field.getAnnotation(Column.class);
		if (column != null) {
			columnName = column.name();
		}
		return StringUtils.isNotEmpty(columnName) ? columnName : field.getName().toLowerCase();
	}

	private static String idCondition(List<String> idNames, Serializable p) {
		int count = 0;
		String condition = "";
		if (idNames.size() > 1) {
			Class<? extends Serializable> pClass = p.getClass();
			Field[] fields = pClass.getDeclaredFields();
			if (fields == null || fields.length <= 0) {
				throw new IllegalArgumentException("Error: Here is no field in Class: " + p.getClass().getName() + "!");
			}
			for (Field field : fields) {
				String columnName = getColumnName(field);
				if (!"serialversionuid".equals(columnName)) {
					Class<?> type = field.getType();
					field.setAccessible(true);
					Object fieldValue = "";
					try {
						fieldValue = field.get(p);
						condition += " AND ";
						if (fieldValue == null) {
							throw new IllegalArgumentException(
									"Error: Id field " + field.getName() + " can't be null!");
						} else {
							if (String.class.equals(type)) {
								condition += columnName + " = " + String.format(SQL_STRING, fieldValue);
							} else {
								condition += columnName + " = " + fieldValue;
							}
						}
						count += 1;
					} catch (IllegalArgumentException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}
		} else {
			condition += idNames.get(0) + " = ";
			if (String.class.equals(p.getClass())) {
				condition += String.format(SQL_STRING, p);
			} else {
				condition += p;
			}
		}
		return count > 0 ? condition.substring(5) : condition;
	}

}
